/** 
 * <p>Original Author:  jessefreeman</p>
 * <p>Class File: WindowStackLayout.as</p>
 * 
 * <p>Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:</p>
 * 
 * <p>The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.</p>
 * 
 * <p>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.</p>
 * 
 * <p>Licensed under The MIT License</p>
 * <p>Redistributions of files must retain the above copyright notice.</p>
 *
 * <p>Revisions<br/> 
 * 	0.1  Initial version Oct 6, 2008</p>
 *
 */

package  camo.views.components.layouts
{
	import camo.events.WindowEvent;
	import camo.models.IModel;
	import camo.views.components.AbstractComponent;
	import camo.views.components.windows.Window;
	
	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.utils.Dictionary;
	
	public class WindowStackLayout extends Layout
	{
		
		public static const CLOSE_WINDOW:String = "close";
		
		public var defaultWindowID:String;
		protected var _windows:Dictionary;
		protected var _activeWindow:Window;
		protected var _topContainer:AbstractComponent;
		protected var _windowQueue:Array;
		protected var _windowData:Dictionary;
		protected var _windowDisplay:Sprite;
		protected var _windowsInstanceIDs:Array;
		protected var _windowDataIndex:Dictionary;
		
		/**
		 *
		 */
		public function WindowStackLayout(model:IModel = null)
		{
			super(model);
		}
		
		/**
		 * Creates dictionary to hold window instances
		 */ 
		override protected function init(model:IModel):void{
			//
			_windowQueue = new Array();
			
			//TODO should this just use the instance collection?
			_windows = new Dictionary(true);
			_windowsInstanceIDs = new Array();
			
			_windowDataIndex = new Dictionary(true);
			
			super.init(model);
			
			// Create Window Display container and move it below the Window Header Container
			_windowDisplay = new Sprite();
			addToDisplay(_windowDisplay);
			
			close(false);
		}
		
		/**
		 * 
		 */
		public function createWindows(windowList:XMLList, startID:Number = -1):void{
			
			for each ( var data:XML in windowList ) {
				
				indexWindowData(data);
				/* 
				var item : Window = createItem(data) as Window;
				
				// Test to make sure Item is valid
				if(item) {
					registerWindow(item.id, item);
				} */
			}
			/* 
			if (startID > 0)
				changeWindow(_windowsInstanceIDs[startID].id); */
		}
		
		/**
		 * 
		 * @param data
		 * 
		 */		
		public function indexWindowData(data:*):void{
			var tempID:String = data.@id;
			_windowDataIndex[tempID] = data;
		}
		
		/**
		 * 
		 * @param indexID
		 * 
		 */		
		public function getWindowID(indexID:Number):void{
			
		}
		
		/**
		 * called when a window is added to the controller. passed in instance is added to 
		 * the window dictionary and is bound to the supplied id.
		 */
		public function registerWindow(id:String, instance:DisplayObject):Boolean{
			if(_windows[id]){
				// return failure to register window and exit out of function
				return false;
			}else{
				_windows[id] = instance;
				_windowsInstanceIDs.push(instance);
				// Check to see if default is set. If not, set the first window to be registered as default
				if(!defaultWindowID)
					defaultWindowID = id;
				// return success
				return true;
			}
		}
		
		/**
		 * Handles the removal and displaying of new windows. Only windows registered with
		 * the controller can be displayed. Once a window has been found in the dictionary
		 * the last active window is removed and the new window is displayed.
		 */
		public function changeWindow(id:String, passedInData:* = null):void{
			
			if(_activeWindow){
				removeWindow(_activeWindow);
			}
			
			if(!_windows[id]){
				
				var item : Window = createItem(_windowDataIndex[id]) as Window;
				
				// Test to make sure Item is valid
				if(item) {
					registerWindow(item.id, item);
				}
				
			}
			
			var nextWindow:Window = _windows[id];
			// TODO add tweens to show and hide windows
			showWindow(nextWindow,passedInData);
			
			refresh();
		}
		
		/**
		 * adds important listeners to the window when active. These listeners are for closing
		 * the controller as well as changing the window.
		 */
		protected function addListeners(target:EventDispatcher):void{
			target.addEventListener(WindowEvent.CLOSE,windowAction);
			target.addEventListener(WindowEvent.CHANGE,windowAction);
		}
		
		/**
		 * this removes any listeners from the target. This should always be called when
		 * removing a window.
		 */
		protected function removeListeners(target:EventDispatcher):void{
			target.removeEventListener(WindowEvent.CLOSE,windowAction);
			target.removeEventListener(WindowEvent.CHANGE,windowAction);
		}
		
		/**
		 * This is called when the controller receives a WindowEvent. This switch statement
		 * manages the logic flow of the event.
		 */
		protected function windowAction(event:WindowEvent):void{
			
			var type:String = event.type;
			var data:* = event.data;
			var id:String = event.window_id;
			switch(type){
				
				case WindowEvent.CLOSE:
					close();
				break;
				case WindowEvent.CHANGE:
					//changeWindow(id, data);
				break;
				case WindowEvent.NEXT_WINDOW:
					nextWindow();
				break;
			}
		
		}
		
		/**
		 * This closes the visible display of the component by removing the active window
		 */
		protected function close(fireEvent:Boolean = true):void{
			
			if(fireEvent)
				dispatchEvent(new Event(Event.CLOSE,true,true));
		}
		
		/**
		 * removes a window from the display tree. It also removes that windows event listeners
		 */
		protected function removeWindow(target:Window):void{
			//TODO Hack to test if target is in display tree, must be a better way of doing this
			if(target.stage){
				target.close();
				removeListeners(target);
				_windowDisplay.removeChild(target);
			}
		}
		
		/**
		 * Shows window and adds window event listeners.
		 */
		protected function showWindow(target:Window, data:* = null):void{
			if(_activeWindow){
				removeWindow(_activeWindow);
				_activeWindow = null;	
			}
			
			_activeWindow = target;
			addListeners(_activeWindow);
			_activeWindow.open(data);
			_windowDisplay.addChild(_activeWindow);
		}
		
		/**
		 * 
		 */
		public function nextWindow():void{
			// call next window in _windowQueue
			var nextID:String = _windowQueue.pop();
			changeWindow(nextID);
		}
	}
}